package net.tv90.business.aspect;

import jakarta.security.auth.message.AuthException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import net.tv90.business.aspect.annotation.EnumPermission;
import net.tv90.business.aspect.annotation.RequiredPermission;
import net.tv90.business.util.Result;
import net.tv90.business.util.TokenUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.UriComponentsBuilder;

/**
 * 复制该拦截器到其他业务服务器
 */
@Slf4j
@Component
public class TokenVerifyInterceptor implements HandlerInterceptor {

    @Value("${verify.host-url}")
    String verifyUrl;

    @Autowired
    TokenUtils tokenUtils;

    private final RestTemplate restTemplate;

    public TokenVerifyInterceptor(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //允许CORS同源预检请求
        if (CorsUtils.isPreFlightRequest(request)) {
            return true;
        }

        String token = request.getHeader("Authorization");
        if (StringUtils.isEmpty(token)) {
            token = request.getParameter("token");
        }

        // 此处校验JWT令牌的有效性
        if (!StringUtils.isEmpty(token) && tokenUtils.validToken(token)) {
            try {
                //请求认证服务器，校验用户是否登录
                UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(verifyUrl)
                        .queryParam("token", token)
                        .queryParam("url", request.getRequestURL().toString());
                ResponseEntity<Result> responseEntity = restTemplate.getForEntity(builder.toUriString(), Result.class);
                //处理认证服务器响应
                if (responseEntity.getStatusCode() == HttpStatus.OK
                        && responseEntity.getBody() != null
                        && responseEntity.getBody().getData() instanceof Integer role
                        && handler instanceof HandlerMethod handlerMethod) {
                    RequiredPermission classPermission = handlerMethod.getBeanType().getAnnotation(RequiredPermission.class);
                    RequiredPermission methodPermission = handlerMethod.getMethodAnnotation(RequiredPermission.class);
                    //检查类或方法级别的权限
                    EnumPermission permission = methodPermission != null ? methodPermission.permission() : (classPermission != null ? classPermission.permission() : null);
                    if (permission == null || permission == EnumPermission.ALL) {
                        log.info("校验成功");
                        return true;
                    }
                    Integer permissionCode = permission.ordinal();
                    if (!role.equals(permissionCode)) {
                        //权限不足
                        response.setStatus(HttpStatus.FORBIDDEN.value());
                        log.info("权限不足:{}", role);
                        throw new AuthException("权限不足");
                    } else {
                        log.info("校验成功");
                        return true;
                    }
                }
            } catch (Exception e) {
                log.warn("token校验失败");
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                throw new AuthException("校验失败");
            }

        }

        log.warn("未携带token，校验失败");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        throw new AuthException("校验失败");
    }
}
